package com.dcits.util;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import com.alibaba.fastjson.JSONObject;
import com.dcits.MainTest;
import com.dcits.business.BaseTest;
import com.dcits.util.db.TestDB;
import com.dcits.util.excel.ExcelUtil;
import com.dcits.util.logger.Logger;
import com.dcits.util.prop.Prop;
import com.dcits.util.prop.PropKit;

/**
 * 常用工具方法汇总
 * @author xuwangcheng
 * @version 2018.3.22
 *
 */
public class DcitsUtil {
	
	public static final Logger logger = Logger.getLogger(DcitsUtil.class);
	
	public static final String FULL_DATE_PATTERN = "yyyy-MM-dd HH:mm:ss";
	/**
	 * excel结果文件存放路径
	 */
	public static String RESULT_EXCEL_PATH;
	/**
	 * html版本报告文件存放路径
	 */
	public static String REPORT_FILE_PATH;
	/**
	 * 运行模式：true为本地模式，false为分布式
	 */
	public static boolean LOCAL_MODE;
	/**
	 * grid的hub节点请求地址
	 */
	public static String HUB_REMOTE_URL;
	/**
	 * 截图文件存放位置
	 */
	public static String SCREENSHOT_PATH;
	
	/**
	 * html报告模板路径
	 */
	public static final String REPORT_TEMPLATE_FILE_PATH = "template/webReport.xml";
	
	public static final Map<String, TestDB> dbConnections = new HashMap<String, TestDB>();
	
	static Prop p = PropKit.use("com//dcits//config" + MainTest.dev_name + "//selenium.properties");
	static Prop paramsProp = PropKit.use("com//dcits//config" + MainTest.dev_name + "//initParameter.properties");
	
	static {
		RESULT_EXCEL_PATH = p.get("result.file.path", "result/");
		REPORT_FILE_PATH = p.get("report.file.path", "report/");
		SCREENSHOT_PATH = p.get("screenshot.file.path", "screenshot/");
		LOCAL_MODE = p.getBoolean("localMode", true);
		HUB_REMOTE_URL = p.get("grid.hub.server.url", "http://127.0.0.1:4444/wd/hub");
		getDbConnections();
	}
	
	/**
	 * 获取数据库连接信息
	 */
	private static void getDbConnections() {
		logger.info("获取数据库连接信息...");
		String dbs = p.get("db", "");
		for (String dbName:dbs.split(",")) {
			try {
				dbConnections.put(dbName, TestDB.getInstance(p, dbName));
			} catch (Exception e) {
				// TODO Auto-generated catch block
				logger.error("获取标识为" + dbName + "的数据连接信息失败!", e);
			}
		}
		logger.info("获取数据库连接信息成功:共" + dbConnections.size() + "条!");
	}
	
	public static void closeAllConnection() {
		for (TestDB db:dbConnections.values()) {
			db.closeConnection();
		}
	}
	
	/**
	 * 获取执行列表
	 * @param configPath
	 * @return
	 */
	public static Map<String, List<BaseTest>> getTestCases(String configPath) {
		Prop p = PropKit.use(configPath);
		List<Object> keys = new ArrayList<Object>(p.getProperties().keySet());
		Map<String, List<BaseTest>> cases = new HashMap<String, List<BaseTest>>();
		for (Object key:keys) {
			if (!checkGroupIfExecute(p.get(key.toString()))) continue;
			try {
				BaseTest testCase = (BaseTest) Class.forName(key.toString()).newInstance();
				if (testCase == null) throw new Exception();
				
				if (cases.get(p.get(key.toString())) == null) {
					cases.put(p.get(key.toString()), new ArrayList<BaseTest>());
				} 
				fillingTestData(testCase, null);
				cases.get(p.get(key.toString())).add(testCase);
				
			} catch (Exception e) {
				// TODO: handle exception
				logger.error(key.toString() + "测试用例类不存在,请检查!");
			}			
		}
		return cases;
	}
	
	/**
	 * 输出结果到excel
	 * @param listResult
	 * @return
	 */
	public static String exportResultExcel(List<Map<String, Object>> listResults) {
		if (listResults.size() == 0) {
			logger.info("无测试结果供导出!");
			return null;
		}
		
		String path = RESULT_EXCEL_PATH;
		OutputStream outputStream = null; 
		String fileName = "/自动化测试结果_" + System.currentTimeMillis() + ".xlsx";
		path = path + fileName;
		try {
			//创建excel
			Workbook wb = ExcelUtil.createWorkBook(ExcelUtil.XLSX);
			Sheet sheet = ExcelUtil.createSheet(wb, "测试结果");
			//写入标题
			CellStyle headerStyle = ExcelUtil.createHeadCellStyle(wb);
			String[] titles = new String[]{"测试用例", "测试数据", "测试结果", "耗时(s)", "备注", "完成时间"};
			Row titleRow = sheet.createRow(0);
			
			for (int i = 0;i < titles.length;i ++) {
				Cell cell = titleRow.createCell(i);
				cell.setCellValue(titles[i]);
				cell.setCellStyle(headerStyle);
			}
			
			int j = 1;
			//写入结果
			for (Map<String, Object> result:listResults) {
				Row row = sheet.createRow(j);
				row.createCell(0).setCellValue(result.get(BaseTest.RESULT_CASE_ATTRIBUTE_NAME).toString());
				row.createCell(1).setCellValue(result.get(BaseTest.RESULT_TEST_DATA_ATTRIBUTE_NAME).toString());
				row.createCell(2).setCellValue(result.get(BaseTest.RESULT_STATUS_ATTRIBUTE_NAME).toString());
				row.createCell(3).setCellValue(result.get(BaseTest.RESULT_USE_TIME_ATTRIBUTE_NAME).toString());
				row.createCell(4).setCellValue(result.get(BaseTest.RESULT_MARK_ATTRIBUTE_NAME).toString());
				row.createCell(5).setCellValue(result.get(BaseTest.RESULT_FINISH_TIME_ATTRIBUTE_NAME).toString());			
				j++;
				sheet.autoSizeColumn(j);
			}
								
			outputStream = new FileOutputStream(new File(path));
			
			wb.write(outputStream); 
			
		} catch (Exception e) {
			// TODO: handle exception
			logger.error("写Excel文件失败:文件路径" + RESULT_EXCEL_PATH + fileName, e);
		} finally {
			if (outputStream != null) {
				try {
					outputStream.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}				
		
		return path;
	}
	
	public static final void fillingTestData(BaseTest test, Map<String, String> params) {
		Field[] fields = test.getClass().getDeclaredFields();
		for (Field f:fields) {
			String v = null;
			if (params != null && params instanceof Map) {
				v = params.get(f.getName());
			}
			
			if (v == null) {
				v = paramsProp.get(f.getName());
			}
			
			if (v == null) {
				logger.info(test.getClass().getSimpleName() + "中定义的属性" + f.getName() + "无法在配置中查询到！");
				continue;
			}
			if (f.getType().getName().equals("java.lang.String")) {				
				try {
					f.set(test, v);
				} catch (IllegalArgumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} else {
				logger.info(test.getClass().getSimpleName() + "中定义的属性" + f.getName() + "不是String类型,无法自动赋值!");
			}
		}
	}
	
	
	/**
	 * 生成html版本的测试报告
	 * @param listResults
	 * @return
	 */
	public static String generateReport(List<Map<String, Object>> listResults, Map<String, Object> reportInfo) {
		if (listResults.size() == 0) {
			logger.info("无测试结果供生成!");
			return null;
		}
		
		//转换数据指定json格式		
		reportInfo.put("cases", listResults);
		String reportDetails = JSONObject.toJSONString(reportInfo);
		
		
		String path = REPORT_FILE_PATH + "/" + String.valueOf(System.currentTimeMillis()) + ".html";
		//获取模板
		File templateFile = new File(REPORT_TEMPLATE_FILE_PATH);
		BufferedOutputStream bos = null;
		FileInputStream fis = null;
		String encoding = "UTF-8";
		
		try {
			bos = new BufferedOutputStream(new FileOutputStream(path));
			fis = new FileInputStream(templateFile);
			//读取模板内容
			Long fileLength = templateFile.length();
			byte[] filecontent = new byte[fileLength.intValue()];
			
			fis.read(filecontent);			
			String html = new String(filecontent, encoding);
			
			//替换重要信息
			html = html.replace("#JSON_STRING__JSON_STRING#", reportDetails);
			
			//写入文件
			bos.write(html.toString().getBytes(encoding));
			bos.flush();
		} catch (Exception e) {
			// TODO: handle exception
			logger.error("测试报告生成失败：" + path, e);
			path = null;
		} finally {
			if (bos != null) {
				try {
					bos.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}			
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		return path;
		
	}
	
	/**
	 * 日期格式化转string
	 * @param date
	 * @param format
	 * @return
	 */
	public static String dataFormat(Date date, String format) {
		DateFormat dateFormat = new SimpleDateFormat(format); 
		return dateFormat.format(date);
	}
	
	/**
	 * 当前日期的String返回
	 * @return
	 */
	public static String getFormatCurrentTime() {
		return getFormatCurrentTime(null);
	}
	
	/**
	 * 当前日期的String返回
	 * @param dateFormate 日期格式
	 * @return
	 */
	public static String getFormatCurrentTime(String dateFormate) {
		if (StringUtils.isBlank(dateFormate)) dateFormate = FULL_DATE_PATTERN;
		return dataFormat(new Date(), dateFormate);
	}
	
	/**
	 * 检查该测试用例所属组是否准许/不准许进行本次测试
	 * @param groupName
	 * @return
	 */
	public static boolean checkGroupIfExecute(String groupName) {
		if (MainTest.executeGroupName.length == 0) {
			return true;
		}
		for (String name:MainTest.executeGroupName) {
			if (groupName.equals(name)) {
				return false;
			}
		}
		return true;
	}
}
